package com.sc.nft.helper;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.sc.nft.config.hna.HnaConfig;
import com.sc.nft.dao.UserHnaExtDao;
import com.sc.nft.dao.WithdrawBankCardDao;
import com.sc.nft.dto.HnaDiscardDto;
import com.sc.nft.dto.HnaRefundDto;
import com.sc.nft.entity.UserHnaExt;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.WithdrawBankCard;
import com.sc.nft.enums.AccountStatusEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.hna.form.BaseTransForm;
import com.sc.nft.hna.form.R009TransForm;
import com.sc.nft.hna.form.T003TransForm;
import com.sc.nft.hna.form.T005TransForm;
import com.sc.nft.sup.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.Map;

@Component
@RequiredArgsConstructor
@Slf4j
public class HnaPayHelper {

  private final HnaConfig hnaConfig;
  private final WithdrawBankCardDao withdrawBankCardDao;
  private final UserHnaExtDao userHnaExtDao;

  public JSONObject refund(UserInfo userInfo, HnaRefundDto dto) {
    return this.postHna(
        T005TransForm.generateParam(hnaConfig, dto),
        T005TransForm.MAIN_URL,
        T005TransForm.TRAN_CODE);
  }

  public String discard(UserInfo userInfo, HnaDiscardDto dto) {
    WithdrawBankCard withdrawBankCard = withdrawBankCardDao.getById(dto.getCardId());
    if (null == withdrawBankCard) {
      throw new GlobalRunTimeException("银行卡不存在");
    }
    if (!withdrawBankCard.getUserId().equals(userInfo.getId())) {
      throw new GlobalRunTimeException("银行卡不存在");
    }
    UserHnaExt userHnaExt = userHnaExtDao.getByUserId(userInfo.getId());
    this.postHna(
        R009TransForm.generateParam(
            userHnaExt.getUserNo(), hnaConfig, withdrawBankCard.getRelatedCardNo()),
        R009TransForm.MAIN_URL,
        R009TransForm.TRAN_CODE);
    withdrawBankCard.setStatus(false);
    withdrawBankCard.updateById();
    return "成功";
  }

  public JSONObject transfer(UserInfo userInfo, String tranAmount) {
    String userNo = this.needOpenAccount(userInfo);
    return this.postHna(
        T003TransForm.generateParam(hnaConfig, userNo, tranAmount),
        T003TransForm.MAIN_URL,
        T003TransForm.TRAN_CODE);
  }

  public JSONObject c2cTransfer(String from, String to, String amount) {
    return this.postHna(
        T003TransForm.customGenerateParam(hnaConfig, from, to, amount),
        T003TransForm.MAIN_URL,
        T003TransForm.TRAN_CODE);
  }

  private String needOpenAccount(UserInfo userInfo) {
    UserHnaExt userHnaExt = userHnaExtDao.getByUserId(userInfo.getId());
    Assert.notNull(userHnaExt, () -> new GlobalRunTimeException("用户未开户"));
    Assert.isTrue(
        AccountStatusEnum.SUCCESS.equals(userHnaExt.getStatus()),
        () -> new GlobalRunTimeException("用户未开户"));
    Assert.isTrue(
        StringUtils.isNotBlank(userHnaExt.getUserNo()), () -> new GlobalRunTimeException("用户未开户"));
    return userHnaExt.getUserNo();
  }

  public JSONObject postHna(Map<String, Object> param, String url, String tranCode) {
    log.info("请求新生接口时，入参：{}", JSONObject.toJSONString(param));
    String result = HttpUtil.post(url, param);
    log.info("新生支付接口返回结果：{}", result);
    if (StringUtils.isBlank(result)) {
      throw new GlobalRunTimeException(ErrorCode.SYS_ERROR);
    }
    JSONObject jsonObject = JSONObject.parseObject(result);
    String resultCode = jsonObject.getString("resultCode");
    if (!"0000".equals(resultCode) && !"9999".equals(resultCode)) {
      log.error(
          "新生支付接口请求出错，错误码：{}，错误信息：{}",
          jsonObject.getString("errorCode"),
          jsonObject.getString("errorMsg"));
      throw new GlobalRunTimeException(jsonObject.getString("errorMsg"));
    }
    String verifyFieldStr = BaseTransForm.getVerifyDataByTranCode(tranCode, jsonObject);
    Sign sign = SecureUtil.sign(SignAlgorithm.SHA1withRSA, null, hnaConfig.getHnaPubKey());
    if (!sign.verify(
        verifyFieldStr.getBytes(), Base64.decode(jsonObject.getString("signValue").getBytes()))) {
      log.error("新生支付接口返回参数验签不通过");
      throw new GlobalRunTimeException(ErrorCode.SYS_ERROR);
    }
    return jsonObject;
  }

  public void checkNotifySign(JSONObject jsonObject, String verifyFieldStr) {
    log.info("新生支付快捷支付异步返回结果：{}", jsonObject.toJSONString());
    log.info("快捷支付异步通知准备验签数据：{}", verifyFieldStr);
    String signValue = URLDecoder.decode(jsonObject.getString("signValue"), StandardCharsets.UTF_8);
    Sign sign = SecureUtil.sign(SignAlgorithm.SHA1withRSA, null, hnaConfig.getHnaPubKey());
    if (!sign.verify(verifyFieldStr.getBytes(), Base64.decode(signValue.getBytes()))) {
      log.error("新生快捷支付异步回调接口返回参数验签不通过");
      throw new GlobalRunTimeException(ErrorCode.SYS_ERROR);
    }
  }
}
